package com.ts.camera2.TsCamera

import android.content.Context
import android.opengl.GLES20.GL_FLOAT
import android.opengl.GLES20.GL_LUMINANCE
import android.opengl.GLES20.glEnableVertexAttribArray
import android.opengl.GLES20.glUniform1i
import android.opengl.GLES20.glUniformMatrix4fv
import android.opengl.GLES20.glVertexAttribPointer
import android.opengl.GLES30
import android.opengl.GLSurfaceView
import android.opengl.Matrix
import android.util.AttributeSet
import android.util.Log
import com.ts.audiocamera.R
import com.ts.opengl.simpleDraw.openglUtil
import com.ts.utils.OpenglGetError
import com.ts.utils.TransformMatrix
import java.nio.ByteBuffer
import java.nio.FloatBuffer
import java.nio.IntBuffer
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10


class GLCameraSurfaceView: GLSurfaceView, GLSurfaceView.Renderer {


    constructor(context: Context,att:AttributeSet):super(context,att){
        setEGLContextClientVersion(2)
        setRenderer(this)
        renderMode= RENDERMODE_WHEN_DIRTY
    }



    private val vertices = floatArrayOf(
        // positions         //color              // texture coords
        -1.0f,  1.0f, 0.0f,   1.0f, 0.0f, 0.0f,   0.0f, 0.0f, // top right
        -1.0f, -1.0f, 0.0f,   1.0f, 0.0f, 1.0f,   0.0f, 1.0f, // bottom right
        1.0f, 1.0f, 0.0f,   1.0f, 0.0f, 1.0f,   1.0f,0.0f, // bottom left
        1.0f,  -1.0f, 0.0f,   0.0f, 0.5f, 1.0f,   1.0f, 1.0f  // top left
    )
    private val indeices = intArrayOf(
        // 注意索引从0开始!
        // 此例的索引(0,1,2,3)就是顶点数组vertices的下标，
        // 这样可以由下标代表顶点组合成矩形

        0, 1, 2, // 第一个三角形
        1, 2, 3  // 第二个三角形
    )

    var vao=IntArray(1)
    var vbo=IntArray(1)
    var ebo=IntArray(1)
    var texture=IntArray(3)
    val element: FloatBuffer by lazy{
        openglUtil.createFloatBuffer(vertices)
    }

    val indexData: IntBuffer by lazy {
        openglUtil.createIntBuffer(indeices)
    }

//    private  val TAG = "GLCameraSurfaceView"
    var program=0;

    var s_textureY=0;
    var s_textureU=0;
    var texturev=0;
   var m_MVPHandle=0;
    fun getOriginalMatrix(): FloatArray {
        return floatArrayOf(
            1f, 0f, 0f, 0f,
            0f, 1f, 0f, 0f,
            0f, 0f, 1f, 0f,
            0f, 0f, 0f, 1f
        )
    }

    private  val TAG = "GLCameraSurfaceView"

    var sizeHandler=0;
//    val matrix = getOriginalMatrix() // 初始化一个矩阵，Matrix.FLT_SIZE通常是16
    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        GLES30.glClearColor(1f, 1f, 1f, 1f)
         Log.e(TAG,OpenglGetError.getError()+"--21-232")
        program=openglUtil.createProgram(context, R.raw.camera_preview_vert, R.raw.camera_preview_frag)
    Log.e(TAG,OpenglGetError.getError()+"--2-232")
        s_textureY=GLES30.glGetUniformLocation(program,"s_textureY")
    Log.e(TAG,OpenglGetError.getError()+"--32-232")
        s_textureU=GLES30.glGetUniformLocation(program,"s_textureU")
    Log.e(TAG,OpenglGetError.getError()+"--33-232")
        texturev=GLES30.glGetUniformLocation(program,"s_textureV")
    Log.e(TAG,OpenglGetError.getError()+"--34-232")
        m_MVPHandle = GLES30.glGetUniformLocation(program, "MVP");
    Log.e(TAG,OpenglGetError.getError()+"--r4-"+sizeHandler)
        sizeHandler=GLES30.glGetUniformLocation(program,"texSize")
    Log.e(TAG,OpenglGetError.getError()+"---"+sizeHandler)

//        Matrix.rotateM(matrix,0, (Math.PI*2f).toFloat(),0.0f,0.0f,1.0f)
        //使用 vbo,vao 优化数据传递
        //创建 VAO
        GLES30.glGenVertexArrays(1, vao, 0)
        // //创建 VBO
        GLES30.glGenBuffers(1, vbo, 0)
        //绑定 VAO ,之后再绑定 VBO
        GLES30.glBindVertexArray(vao[0])
        //绑定VBO
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0])
        GLES30.glBufferData(
            GLES30.GL_ARRAY_BUFFER,
            element.capacity() * 4,
            element,
            GLES30.GL_STATIC_DRAW
        )
        Log.e(TAG,OpenglGetError.getError()+"---"+sizeHandler)
        //创建 ebo
        GLES30.glGenBuffers(1, ebo, 0)
        //绑定 ebo 到上下文
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, ebo[0])
        //昂丁
        GLES30.glBufferData(
            GLES30.GL_ELEMENT_ARRAY_BUFFER,
            indexData.capacity() * 4,
            indexData,
            GLES30.GL_STATIC_DRAW
        )
        Log.e(TAG,OpenglGetError.getError()+"---")

        //位置信息解析
        element.position(0)
        glVertexAttribPointer(0,3, GL_FLOAT,false,8*4,0)
        glEnableVertexAttribArray(0)
//        Log.e(TAG,OpenglGetError.getError()+"---")
        element.position(3)
        glVertexAttribPointer(1,3, GL_FLOAT,false,8*4,3*4)
        GLES30.glEnableVertexAttribArray(1)
//        Log.e(TAG,OpenglGetError.getError()+"---")
        element.position(6)
        GLES30.glVertexAttribPointer(
            2, 2, GLES30.GL_FLOAT,
            false, 8 * 4, 6*4 //需要指定颜色的地址 3 * 4
        )
        GLES30.glEnableVertexAttribArray(2)

//        Log.e(TAG,OpenglGetError.getError()+"---")
//        CreateTextures()
//           return ;
//        }
//        Log.e(TAG,OpenglGetError.getError()+"---")
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)
        GLES30.glBindVertexArray(0)
        //注意顺序，ebo 要在 eao 之后
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0)
//        Log.e(TAG,OpenglGetError.getError()+"---")
    }

    var mImageCamera:ImageCamera?=null


    fun CreateTextures():Boolean{
        if (mImageCamera==null){
            return false;
        }
//        Log.e(TAG,OpenglGetError.getError()+"---")

        val yWidth=mImageCamera?.width!!
        val yHeight=mImageCamera?.height!!
        GLES30.glActiveTexture( GLES30.GL_TEXTURE0);
        GLES30.glGenTextures(texture.size,texture,0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,texture[0])
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR)
//
        GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE, yWidth,  yHeight, 0,
            GLES30.GL_LUMINANCE,
            GLES30.GL_UNSIGNED_BYTE,
            null)

        if (texture[0]==0) {
            return false;
        }
//        Log.e(TAG,OpenglGetError.getError()+"---")


        GLES30.glActiveTexture( GLES30.GL_TEXTURE1);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,texture[1])
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR)
        GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE,
            yWidth/2, yHeight/2, 0, GLES30.GL_LUMINANCE,
            GLES30.GL_UNSIGNED_BYTE,
            null)
        if (texture[1]==0) {
            return false;
        }
//
        GLES30.glActiveTexture( GLES30.GL_TEXTURE2);

//        Log.e(TAG,OpenglGetError.getError()+"---")
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,texture[2])
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR)
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR)
        GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_LUMINANCE, yWidth/2,
            yHeight/2, 0, GLES30.GL_LUMINANCE,
            GLES30.GL_UNSIGNED_BYTE,
            null);
        if (texture[2]==0) {
            return false;
        }

        return true;
    }

    private

    fun  UpdateTextures():Boolean{

//        if (mImageCamera?.byteArray==null||mImageCamera?.byteArray?.size==0){
//
//            return false
//        }
        if(texture[0]==0&&texture[1]==0&&texture[1]==0&&!CreateTextures()){

            return false
        }

//        if (mImageCamera?.byteArray?.size!!>0) {
            mImageCamera?.let {
                GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
                GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, texture[0])


                GLES30.glTexImage2D(
                    GLES30.GL_TEXTURE_2D,
                    0,
                    GLES30.GL_LUMINANCE,
                    it.width,
                    it.height,
                    0,
                    GLES30.GL_LUMINANCE,
                    GLES30.GL_UNSIGNED_BYTE,
                    mImageCamera?.p1
                )


                    GLES30.glActiveTexture(GLES30.GL_TEXTURE1)
                    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, texture[1])

                    GLES30.glTexImage2D(
                        GLES30.GL_TEXTURE_2D, 0, GL_LUMINANCE, it.width / 2,
                        it.height / 2, 0,
                        GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE, mImageCamera?.p2
                    )



                    GLES30.glActiveTexture(GLES30.GL_TEXTURE2)
                    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, texture[2])
                    GLES30.glTexImage2D(
                        GLES30.GL_TEXTURE_2D, 0, GL_LUMINANCE,
                        it.width / 2,
                        it.height / 2, 0,
                        GL_LUMINANCE, GLES30.GL_UNSIGNED_BYTE,
                        mImageCamera?.p3
                    )

            }
        mImageCamera?.p1?.clear()
        mImageCamera?.p2?.clear()
        mImageCamera?.p3?.clear()
//        }
        return true
    }




    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {

        GLES30.glViewport(0, 0, width, height);
    }


    fun useProgram(){
        GLES30.glUseProgram(program)
    }


    var isok=false;

    var lock=ReentrantLock()
    private val buf = floatArrayOf(1280.0f,720.0f)
    override fun onDrawFrame(gl: GL10?) {
        lock.lock()
        GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)
        GLES30.glDisable(GLES30.GL_CULL_FACE)

        if (!UpdateTextures()){
            lock.unlock()
            return
        }
//        90---1.57079640.0=---0.0-----1.0=-==1.0
//        rotate 90,1.57,0.00000,0.00000,-1.00000,1.00000
        useProgram();
        UpdateMVPMatrix()
        glUniformMatrix4fv(m_MVPHandle,1,false,mMVPMatrix,0)



        GLES30.glUniform2fv(sizeHandler,1,openglUtil.createFloatBuffer(buf))

        GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
        glUniform1i(s_textureY,0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,texture[0])

        GLES30.glActiveTexture(GLES30.GL_TEXTURE1)
        glUniform1i(s_textureU,1)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,texture[1])

        GLES30.glActiveTexture(GLES30.GL_TEXTURE2)
        glUniform1i(texturev,2)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,texture[2])

        GLES30.glBindVertexArray(vao[0])

        GLES30.glDrawElements(GLES30.GL_TRIANGLE_STRIP,indeices.size,GLES30.GL_UNSIGNED_INT,0)
        lock.unlock()
    }


//    var byteArray: CopyOnWriteArrayList<ByteBuffer> = CopyOnWriteArrayList ()


    fun setImageData(data: ByteArray, width: Int, height: Int) {

        mImageCamera=ImageCamera(width,height,ByteBuffer.wrap(data),
            ByteBuffer.wrap(data.copyOfRange(width * height,data.size-1)),
            ByteBuffer.wrap(data.copyOfRange(width * height+width * height/4,data.size-1)))



    }
    var mMVPMatrix = FloatArray(16)

    private fun UpdateMVPMatrix(){
        var fFactorX = 1.0f
        var fFactorY = 1.0f
        if (mTransformMatrix.mirror==1){
            fFactorX=-1.0f;
        }else{
            fFactorY=-1.0f;
        }
        var fRotate: Float = (Math.PI * mTransformMatrix.degree?.toFloat()!! * 1.0f / 180).toFloat()

        if (mTransformMatrix.mirror == 0) {
            if (mTransformMatrix.degree == 270) {
                fRotate = Math.PI.toFloat() * 0.5f;
            } else if (mTransformMatrix.degree == 180) {
                fRotate = Math.PI.toFloat();
            } else if (mTransformMatrix.degree == 90) {
                fRotate = Math.PI.toFloat() * 1.5f;
            }
        } else if (mTransformMatrix.mirror == 1) {
            if (mTransformMatrix.degree == 90) {
                fRotate = Math.PI.toFloat() * 0.5f;
            } else if (mTransformMatrix.degree == 180) {
                fRotate = Math.PI.toFloat();
            } else if (mTransformMatrix.degree == 270) {
                fRotate = Math.PI.toFloat() * 1.5f;
            }
        }
        var mViewMatrix = FloatArray(16)
        var mProjectMatrix = FloatArray(16)
        mMVPMatrix= FloatArray(16)
        var model= FloatArray(16)
        Matrix.setIdentityM(model,0);
//         Log.e(TAG,"tr1"+mTransformMatrix.toString())
        var ratio= android.R.attr.width.toFloat() / android.R.attr.height
//        Matrix.perspectiveM(mProjectMatrix, 0,45.0f,ratio,0.1f,200.0f)
        Matrix.orthoM(mProjectMatrix,0,
            -1.0f,1.0f,-1.0f,1.0f,0.0f,1.0f)
        Matrix.setLookAtM(mViewMatrix,0,0f,0f,1.0f,
            0f,0f,0f,0f,1.0f,0f);
//        Log.e(TAG,"\"----------------------------------\""+fFactorX* mTransformMatrix.scaleX!!+""+fFactorY* mTransformMatrix.scaleY!!)
//        Matrix.scaleM(model,0,fFactorX* mTransformMatrix.scaleX!!,
//            fFactorY* mTransformMatrix.scaleY!!,1.0f)
//
//
//        Matrix.rotateM(model,0,fRotate,0.0f,0.0f,1.0f)


        model= floatArrayOf(0.0f,1.0f,0.0f,0.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f,0.0f,0.0f,0.0f,1.0f)


        Matrix.translateM(model,0, mTransformMatrix.translateX!!,
                mTransformMatrix.translateY!!,0.0f)

//        Log.e(TAG,"SetMVP real: "+mTransformMatrix.degree+"---"+fRotate+
//            mTransformMatrix.translateX.toString()
//                    +"=---"+mTransformMatrix.translateY
//                    +"----" +(fFactorX * mTransformMatrix.scaleX!!).toString()
//                    +"=-=="+(fFactorY * mTransformMatrix.scaleY!!).toString());
        Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0)
        Matrix.multiplyMM(mMVPMatrix,0,mMVPMatrix,0,model,0)

    }


    var mTransformMatrix= TransformMatrix();

    private fun native_SetTransformMatrix(translateX:Float , translateY:Float , scaleX:Float ,scaleY: Float ,degree: Int , mirror:Int ){

        mTransformMatrix.degree=degree;
        mTransformMatrix.translateX=translateX;
        mTransformMatrix.translateY=translateY;
        mTransformMatrix.scaleX=scaleX;
        mTransformMatrix.mirror=mirror;
        mTransformMatrix.scaleY=scaleY;
//        Log.e(TAG,mTransformMatrix?.toString()+"===")
        UpdateMVPMatrix();

    }

    public fun setTransformMatrix(degree:Int ,  mirror:Int) {
        native_SetTransformMatrix(0.0f,0.0f,1.0f,1.0f,degree,mirror)
    }
}